package com.spring.springboot.sys.core.config;

import com.spring.springboot.sys.core.interceptor.RestAuthenticationEntryPoint;
import com.spring.springboot.sys.core.interceptor.RestfulAccessDeniedHandler;
import com.spring.springboot.sys.jwt.JwtAuthenticationTokenFilter;
import com.spring.springboot.sys.jwt.JwtTokenUtil;
import com.spring.springboot.sys.jwt.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

/**
 * @author admin
 * @EnableWebSecurity 开启WebSecurity模式
 * @date 2021-04-20 17:20
 * @description Security基础配置类
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(JwtTokenUtil.class)
public class SecurityConfig implements WebMvcConfigurer {

    @Resource
    private UserDetailsServiceImpl userDetailsService;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        // 由于使用的是JWT，我们这里不需要csrf
        httpSecurity.csrf().disable()
                // 基于token,所以不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 跨域预检请求
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                //swagger静态资源
                .antMatchers("/swagger-ui.html",
                        "/swagger-ui/*",
                        "/swagger-resources/**",
                        "/v2/api-docs",
                        "/v3/api-docs",
                        "/webjars/**",
                        "/doc.html").permitAll()
                // login
                .antMatchers("/api/system/**").permitAll()
                //wabSocket
                .antMatchers("/api/pushMessage/**").permitAll()
                //剩余自定义
                //.antMatchers("/level1/**").hasRole("vip1")
                // 其他所有请求需要身份认证
                .anyRequest().authenticated();

        //管理userDetailsService
        httpSecurity.userDetailsService(userDetailsService);
        // 禁用缓存
        httpSecurity.headers().cacheControl();
        // 添加JWT filter
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        httpSecurity.exceptionHandling().accessDeniedHandler(restfulAccessDeniedHandler()).authenticationEntryPoint(restAuthenticationEntryPoint());

        return httpSecurity.build();
    }

    /**
     * 放行静态资源
     */
    //@Bean
    //public WebSecurityCustomizer webSecurityCustomizer() {
    //    return (web) -> web.ignoring().antMatchers("/swagger-ui.html",
    //            "/swagger-ui/*",
    //            "/swagger-resources/**",
    //            "/v3/api-docs",
    //            "/webjars/**",
    //            "/doc.html");
    //}

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 自定义WebUserDetails
     */
    //@Bean
    //public UserDetailsService userDetailsService() {
    //    return s -> new WebUserDetails(new UserInfo(1L, "宋义州", "18339465818", "syz961224.."));
    //}

    /**
     * 获取AuthenticationManager（认证管理器），登录时认证使用
     *
     * @param authenticationConfiguration
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * token校验过滤
     *
     * @return
     */
    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

    /**
     * 未登录或者未授权
     *
     * @return AuthenticationEntryPoint
     */
    @Bean
    public AuthenticationEntryPoint restAuthenticationEntryPoint() {
        return new RestAuthenticationEntryPoint();
    }

    /**
     * 接口没有权限
     *
     * @return AccessDeniedHandler
     */
    @Bean
    public AccessDeniedHandler restfulAccessDeniedHandler() {
        return new RestfulAccessDeniedHandler();
    }
}
